﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using DiscoveryLogic.Common.Utilities;
using DiscoveryLogic.DataViz.NetworkDiagram.NetworkData;
using DiscoveryLogic.WindowsUserControl.Codes;

namespace DiscoveryLogic.DataViz.NetworkDiagram
{
    /// <summary>
    /// 
    /// </summary>
    public partial class VisualSettings : Form
    {
        private readonly string _NetworkName;
        private NetworkVisualSetting _VizSetting;
		/// <summary>
		/// 
		/// </summary>
		/// <param name="networkName"></param>
		/// <param name="vizSetting"></param>
        public delegate void OnVizSettingUpdated(string networkName, NetworkVisualSetting vizSetting);

        public event OnVizSettingUpdated VizSettingUpdated;
        /// <summary>
        /// 
        /// </summary>
        public VisualSettings(string networkName, NetworkVisualSetting vizSetting)
        {
            this._NetworkName = networkName;
            this._VizSetting = vizSetting;
            InitializeComponent();
        }

        private void VisualSettings_Load(object sender, EventArgs e)
        {
            this.cbo_VShape.Items.Clear();
            for(int i=0;i<=4;i++)
            {
                VerticeShape verticeShape = (VerticeShape) i;
                this.cbo_VShape.Items.Add(verticeShape.ToString());
            }
            this.cbo_VShape.SelectedIndex = (int) this._VizSetting.VerticeShape;
            this.cbo_VColor.Items.Clear();
            this.cbo_EColor.Items.Clear();
            Array colors = Enum.GetValues(typeof (KnownColor));
            foreach(object item in colors)
            {
                this.cbo_EColor.Items.Add(((KnownColor) item).ToString());
                this.cbo_VColor.Items.Add(((KnownColor)item).ToString());
            }
            Color vColor = this._VizSetting.VerticeColor;
            for(int i=0;i<cbo_VColor.Items.Count;i++)
            {
                KnownColor kColor = (KnownColor) Enum.Parse(typeof (KnownColor), this.cbo_VColor.Items[i].ToString());
                Color color = Color.FromKnownColor(kColor);
                if(color.R==vColor.R && color.G==vColor.G && color.B==vColor.B)
                {
                    this.cbo_VColor.SelectedIndex = i;
                    break;
                }
            }
            this.tk_VColorTransparency.Value = vColor.A;
            Color eColor = this._VizSetting.EdgeColor;
            for (int i = 0; i < cbo_EColor.Items.Count; i++)
            {
                KnownColor kColor = (KnownColor)Enum.Parse(typeof(KnownColor), this.cbo_EColor.Items[i].ToString());
                Color color = Color.FromKnownColor(kColor);
				if (color.R == eColor.R && color.G == eColor.G && color.B == eColor.B)
                {
                    this.cbo_EColor.SelectedIndex = i;
                    break;
                }
            }
			this.cbo_EdgeLineStyles.Items.Clear();
			for (int i = 0; i <= 1;i++)
			{
				EdgeLineStyle lineStyle = (EdgeLineStyle) i;
				this.cbo_EdgeLineStyles.Items.Add(lineStyle.ToString());
			}
        	this.cbo_EdgeLineStyles.SelectedIndex = (int) this._VizSetting.LineStyle;
			this.tk_VSize.Value = (int)this._VizSetting.VerticeSize.Width;
            this.lbl_VSize.Text = this.tk_VSize.Value.ToString();
            this.tk_EThickness.Value = (int)this._VizSetting.EdgeThickness;
            this.lbl_EThickness.Text = this.tk_EThickness.Value.ToString();

            if(!string.IsNullOrEmpty(this._VizSetting.EdgeColorCode))
                this.ck_EColorConditional.Checked = true;
            else
                this.ck_EColorConditional.Checked = false;
            if(!string.IsNullOrEmpty(this._VizSetting.EdgeLineStyleCode))
                this.ck_EStyleConditional.Checked = true;
            else
                this.ck_EStyleConditional.Checked = false;
            if(!string.IsNullOrEmpty(this._VizSetting.EdgeThicknessCode))
                this.ck_EThicknessConditional.Checked = true;
            else
                this.ck_EThicknessConditional.Checked = false;
            if(!string.IsNullOrEmpty(this._VizSetting.VerticeColorCode))
                this.ck_VColorConditional.Checked = true;
            else
                this.ck_VColorConditional.Checked = false;
            if(!string.IsNullOrEmpty(this._VizSetting.VerticeShapeCode))
                this.ck_VShapeConditional.Checked = true;
            else
                this.ck_VSizeConditional.Checked = false;
            if(!string.IsNullOrEmpty(this._VizSetting.VerticeSizeCode))
                this.ck_VSizeConditional.Checked = true;
            else
                this.ck_VSizeConditional.Checked = false;
        }

        private void tk_VSize_Scroll(object sender, EventArgs e)
        {
            this.lbl_VSize.Text = this.tk_VSize.Value.ToString();
        }

        private void tk_EThickness_Scroll(object sender, EventArgs e)
        {
            this.lbl_EThickness.Text = this.tk_EThickness.Value.ToString();
        }

        private void cbo_VShape_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_VShape.SelectedIndex>=0)
            {
                VerticeShape verticeShape = (VerticeShape) this.cbo_VShape.SelectedIndex;
                KnownColor knownColor = KnownColor.Blue;
                if(this.cbo_VColor.SelectedIndex>=0)
                {
                    knownColor = (KnownColor) Enum.Parse(typeof (KnownColor), this.cbo_VColor.SelectedItem.ToString());
                }
                Color vColor = Color.FromKnownColor(knownColor);
                vColor = Color.FromArgb(this.tk_VColorTransparency.Value, vColor);
                this.UpdateVerticeImage(verticeShape, vColor);
            }
        }

        private void UpdateVerticeImage(VerticeShape verticeShape, Color color)
        {
            Bitmap img = new Bitmap(this.pic_VShape.Width, this.pic_VShape.Height);
            Graphics g = Graphics.FromImage(img);
            switch (verticeShape)
            {
                case VerticeShape.Circle:
                    g.FillEllipse(new SolidBrush(color), new Rectangle(0, 0, img.Width, img.Height));
                    break;
                case VerticeShape.Square:
                    g.FillRectangle(new SolidBrush(color), new Rectangle(0, 0, img.Width, img.Height));
                    break;
                case VerticeShape.UpTriangle:
                    Point a = new Point(img.Width / 2, 0);
                    Point b = new Point(0, img.Height);
                    Point c = new Point(img.Width, img.Height);
                    g.FillPolygon(new SolidBrush(color), new Point[] { a, b, c });
                    break;
                case VerticeShape.DownTrangle:
                    Point p1 = new Point(img.Width / 2, img.Height);
                    Point p2 = new Point(0, 0);
                    Point p3 = new Point(img.Width, 0);
                    g.FillPolygon(new SolidBrush(color), new Point[] { p1, p2, p3 });
                    break;
                case VerticeShape.Diamond:
                    Point pL = new Point(0, img.Height / 2);
                    Point pT = new Point(img.Width / 2, 0);
                    Point pR = new Point(img.Width, img.Height / 2);
                    Point pB = new Point(img.Width / 2, img.Height);
                    g.FillPolygon(new SolidBrush(color), new Point[] { pL, pT, pR, pB });
                    break;
            }

            g.Dispose();
        	this.pic_VShape.Image = img;
        }

		private void UpdateEdgeImage(EdgeLineStyle lineStyle, Color edgeColor, float thickNess)
		{
			Bitmap img = new Bitmap(this.pic_EColor.Width, this.pic_VShape.Height);
			Graphics g = Graphics.FromImage(img);
			g.Clear(Color.White);
			Pen p=new Pen(edgeColor, thickNess);
			p.DashStyle = DashStyle.Solid;
			if (lineStyle == EdgeLineStyle.Dashed)
				p.DashStyle = DashStyle.Dash;
			Point start=new Point(0,img.Height/2);
			Point end = new Point(img.Width, img.Height /2);
			g.DrawLine(p, start, end);
			g.Dispose();
			this.pic_EColor.Image = img;
		}

    	private void cbo_VColor_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_VColor.SelectedIndex>=0)
            {
                KnownColor knownColor = (KnownColor)Enum.Parse(typeof(KnownColor), this.cbo_VColor.SelectedItem.ToString());
                VerticeShape verticeShape = VerticeShape.Circle;
                if (this.cbo_VColor.SelectedIndex >= 0)
                {
                    verticeShape = (VerticeShape)this.cbo_VShape.SelectedIndex;
                }
                Color vColor = Color.FromArgb(this.tk_VColorTransparency.Value, Color.FromKnownColor(knownColor));
				this.UpdateVerticeImage(verticeShape, vColor);
            }
        }

        private void cbo_EColor_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_EColor.SelectedIndex>=0 && this.cbo_EdgeLineStyles.SelectedIndex>=0)
            {
                KnownColor color = (KnownColor) Enum.Parse(typeof (KnownColor), this.cbo_EColor.SelectedItem.ToString());
            	EdgeLineStyle lineStyle = (EdgeLineStyle) this.cbo_EdgeLineStyles.SelectedIndex;
            	float thickness = (float) this.tk_EThickness.Value;
				this.UpdateEdgeImage(lineStyle, Color.FromKnownColor(color), thickness);
            }
        }

        private void ck_VShapeConditional_CheckedChanged(object sender, EventArgs e)
        {
            if (this.ck_VShapeConditional.Checked)
            {
                this.cbo_VShape.Enabled = false;
                this.btn_EditVShape.Enabled = true;
            }
            else
            {
                this.cbo_VShape.Enabled = true;
                this.btn_EditVShape.Enabled = false;
            }
        }

        private void ck_VSizeConditional_CheckedChanged(object sender, EventArgs e)
        {
            if(this.ck_VSizeConditional.Checked)
            {
                this.tk_VSize.Enabled = false;
                this.btn_EditVSize.Enabled = true;
            }
            else
            {
                this.tk_VSize.Enabled = true;
                this.btn_EditVSize.Enabled = false;
            }
        }

        private void ck_VColorConditional_CheckedChanged(object sender, EventArgs e)
        {
            if(this.ck_VColorConditional.Checked)
            {
                this.cbo_VColor.Enabled = false;
                this.btn_EditVColor.Enabled = true;
            }
            else
            {
                this.cbo_VColor.Enabled = true;
                this.btn_EditVColor.Enabled = false;
            }
        }

        private void ck_EThicknessConditional_CheckedChanged(object sender, EventArgs e)
        {
            if(this.ck_EThicknessConditional.Checked)
            {
                this.tk_EThickness.Enabled = false;
                this.btn_EditEThickness.Enabled = true;
            }
            else
            {
                this.tk_EThickness.Enabled = true;
                this.btn_EditEThickness.Enabled = false;
            }
        }

        private void ck_EColorConditional_CheckedChanged(object sender, EventArgs e)
        {
            if(this.ck_EColorConditional.Checked)
            {
                this.cbo_EColor.Enabled = false;
                this.btn_EditEColor.Enabled = true;
            }
            else
            {
                this.cbo_EColor.Enabled = true;
                this.btn_EditEColor.Enabled = false;
            }
        }

        private void btn_EditVShape_Click(object sender, EventArgs e)
        {
            CodeEditor codeEditor1=new CodeEditor("public VerticeShape GetVerticeShape(int verticeDegree) {");
            codeEditor1.CodeUpdated += new CodeEditor.OnCodeUpdated(codeEditor1_CodeUpdated);
            codeEditor1.Code = this._VizSetting.VerticeShapeCode;
            codeEditor1.Show(this);
        }

        void codeEditor1_CodeUpdated(string code)
        {
            this._VizSetting.VerticeShapeCode = code;
        }

        private void btn_EditVSize_Click(object sender, EventArgs e)
        {
            string args = this.BuildCustomizationMethodArgument();
            CodeEditor codeEditor2 = new CodeEditor("public SizeF GetVerticeSize(" + args + ") {");
            codeEditor2.CodeUpdated += new CodeEditor.OnCodeUpdated(codeEditor2_CodeUpdated);
            codeEditor2.Code = this._VizSetting.VerticeSizeCode;
            codeEditor2.Show(this);
        }

        void codeEditor2_CodeUpdated(string code)
        {
            this._VizSetting.VerticeSizeCode = code;
        }

        private void btn_EditVColor_Click(object sender, EventArgs e)
        {
            CodeEditor editor3 = new CodeEditor("public Color GetVerticeColor(int verticeDegree) {");
            editor3.CodeUpdated += new CodeEditor.OnCodeUpdated(editor3_CodeUpdated);
            editor3.Code = this._VizSetting.VerticeColorCode;
            editor3.Show(this);
        }

        void editor3_CodeUpdated(string code)
        {
            this._VizSetting.VerticeColorCode = code;
        }

        private void btn_EditEThickness_Click(object sender, EventArgs e)
        {
            CodeEditor editor4 = new CodeEditor("public float GetEdgeThickness(double edgeDistance) {");
            editor4.CodeUpdated += new CodeEditor.OnCodeUpdated(editor4_CodeUpdated);
            editor4.Code = this._VizSetting.EdgeThicknessCode;
            editor4.Show(this);
        }

        void editor4_CodeUpdated(string code)
        {
            this._VizSetting.EdgeThicknessCode = code;
        }

        private void btn_EditEColor_Click(object sender, EventArgs e)
        {
            CodeEditor editor5 = new CodeEditor("public Color GetEdgeColor(double edgeDistance) {");
            editor5.CodeUpdated += new CodeEditor.OnCodeUpdated(editor5_CodeUpdated);
            editor5.Code = this._VizSetting.EdgeColorCode;
            editor5.Show(this);
        }

        void editor5_CodeUpdated(string code)
        {
            this._VizSetting.EdgeColorCode = code;
        }

        private void btn_OK_Click(object sender, EventArgs e)
        {
            Color vColor = Color.Blue;
            if(this.cbo_VColor.SelectedIndex>=0)
            {
                KnownColor color = (KnownColor) Enum.Parse(typeof (KnownColor), this.cbo_VColor.SelectedItem.ToString());
                vColor = Color.FromArgb(this.tk_VColorTransparency.Value, Color.FromKnownColor(color));
            }
            this._VizSetting.VerticeColor = vColor;

            VerticeShape vVerticeShape = VerticeShape.Circle;
            if(this.cbo_VShape.SelectedIndex>=0)
                vVerticeShape = (VerticeShape) this.cbo_VShape.SelectedIndex;
            this._VizSetting.VerticeShape = vVerticeShape;

            float vSize = (float) this.tk_VSize.Value;
            this._VizSetting.VerticeSize = new SizeF(vSize, vSize);

            float eThick = (float) this.tk_EThickness.Value;
            this._VizSetting.EdgeThickness = eThick;

            Color eColor = Color.Orange;
            if (this.cbo_EColor.SelectedIndex >= 0)
            {
                KnownColor color = (KnownColor)Enum.Parse(typeof(KnownColor), this.cbo_EColor.SelectedItem.ToString());
                eColor = Color.FromKnownColor(color);
            }
            this._VizSetting.EdgeColor = eColor;

            this._VizSetting.LineStyle = EdgeLineStyle.Solid;
			if(this.cbo_EdgeLineStyles.SelectedIndex>=0)
                this._VizSetting.LineStyle = (EdgeLineStyle)this.cbo_EdgeLineStyles.SelectedIndex;

            if (this.VizSettingUpdated != null)
                this.VizSettingUpdated(this._NetworkName, this._VizSetting);

            this.Close();
        }

		private void ck_EStyleConditional_CheckedChanged(object sender, EventArgs e)
		{
			if(ck_EStyleConditional.Checked)
			{
				this.btn_EditEStyle.Enabled = true;
				this.cbo_EdgeLineStyles.Enabled = false;
			}
			else
			{
				this.btn_EditEStyle.Enabled = false;
				this.cbo_EdgeLineStyles.Enabled = true;
			}
		}

		private void btn_EditEStyle_Click(object sender, EventArgs e)
		{
			CodeEditor editor6 = new CodeEditor("public Color GetEdgeLineStyle(double edgeDistance) {");
			editor6.CodeUpdated += new CodeEditor.OnCodeUpdated(editor6_CodeUpdated);
			editor6.Code = this._VizSetting.LineStyleCode;
			editor6.Show(this);
		}

		void editor6_CodeUpdated(string code)
		{
			this._VizSetting.LineStyleCode = code;
		}

		private void cbo_EdgeLineStyles_SelectedIndexChanged(object sender, EventArgs e)
		{
			if(this.cbo_EdgeLineStyles.SelectedIndex>=0 && this.cbo_EColor.SelectedIndex>=0)
			{
				KnownColor color = (KnownColor)Enum.Parse(typeof(KnownColor), this.cbo_EColor.SelectedItem.ToString());
				EdgeLineStyle lineStyle = (EdgeLineStyle)this.cbo_EdgeLineStyles.SelectedIndex;
				float thickness = (float)this.tk_EThickness.Value;
				this.UpdateEdgeImage(lineStyle, Color.FromKnownColor(color), thickness);
			}
		}

        private void ck_VTransparencyConditional_CheckedChanged(object sender, EventArgs e)
        {
            if(this.ck_VTransparencyConditional.Checked)
            {
                this.btn_EditVTransparency.Enabled = true;
                this.tk_VColorTransparency.Enabled = false;
            }
            else
            {
                this.btn_EditVTransparency.Enabled = false;
                this.tk_VColorTransparency.Enabled = true;
            }
        }

        private void tk_VColorTransparency_Scroll(object sender, EventArgs e)
        {
            if (this.cbo_VColor.SelectedIndex >= 0)
            {
                KnownColor knownColor = (KnownColor)Enum.Parse(typeof(KnownColor), this.cbo_VColor.SelectedItem.ToString());
                VerticeShape verticeShape = VerticeShape.Circle;
                if (this.cbo_VColor.SelectedIndex >= 0)
                {
                    verticeShape = (VerticeShape)this.cbo_VShape.SelectedIndex;
                }
                Color vColor = Color.FromArgb(this.tk_VColorTransparency.Value, Color.FromKnownColor(knownColor));
                this.UpdateVerticeImage(verticeShape, vColor);
            }
        }

        private void btn_EditVTransparency_Click(object sender, EventArgs e)
        {
            CodeEditor editor7 = new CodeEditor("public int GetVerticeColorTransparency(int verticeDegree) {");
            editor7.CodeUpdated += new CodeEditor.OnCodeUpdated(editor7_CodeUpdated);
            editor7.Code = this._VizSetting.VerticeTranspacencyCode;
            editor7.Show(this);
        }

        private void editor7_CodeUpdated(string code)
        {
            this._VizSetting.VerticeTranspacencyCode = code;
        }

        private Dictionary<string,Type> GetNetworkDataFields()
        {
            DataTable dtNetData = new DataTable();
            List<LinkDataObject> linkDOs=new List<LinkDataObject>();
            Network.ReadData(this._NetworkName, ref dtNetData, ref linkDOs);
            Dictionary<string, Type> fieldTypes = new Dictionary<string, Type>();
            if(dtNetData !=null && dtNetData.Rows.Count>0)
            {
                foreach(DataColumn col in dtNetData.Columns)
                {
                    fieldTypes.Add(col.ColumnName, col.DataType);
                }
            }
            return fieldTypes;
        }

        private string BuildCustomizationMethodArgument()
        {
            Dictionary<string, Type> vDataTypes = this.GetNetworkDataFields();
            StringBuilder buffer=new StringBuilder();
            foreach(string vFieldName in vDataTypes.Keys)
            {
                SimpleDataType dataType = SimpleDataTypeUtil.ToSimpleDataType(vDataTypes[vFieldName]);
                if (dataType == SimpleDataType.ComplexType ||
                    dataType == SimpleDataType.StringListType ||
                    dataType == SimpleDataType.IntListType)
                    continue;

                if (buffer.Length > 0)
                    buffer.Append(", ");
                buffer.Append(vDataTypes[vFieldName].Name + " " + vFieldName);
            }
            PropertyInfo[] vProps = typeof (Vertice).GetProperties();
            foreach(PropertyInfo prop in vProps)
            {
                SimpleDataType dataType = SimpleDataTypeUtil.ToSimpleDataType(prop.PropertyType);
                if (dataType == SimpleDataType.ComplexType ||
                    dataType == SimpleDataType.StringListType ||
                    dataType == SimpleDataType.IntListType)
                    continue;

                if (buffer.Length > 0)
                    buffer.Append(", ");
                buffer.Append(prop.PropertyType.Name + " " + prop.Name);
            }
            return buffer.ToString();
        }
    }
}
